package com.lishem.rpc.client.proxy;

import com.lishem.common.data.RpcRequest;
import com.lishem.common.data.RpcResponse;
import com.lishem.common.utils.RequestIdUtil;
import com.lishem.rpc.client.runner.RpcRequestManager;
import com.lishem.rpc.client.runner.RpcRequestPool;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * 动态代理拦截处理器，异步实现
 */
@Component
public class ProxyHelper {

    @Autowired
    private RpcRequestPool rpcRequestPool;

    public <T> T newProxyInstance(Class<T> cls) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);
        enhancer.setCallback(new ProxyCallBackHandler());
        return (T) enhancer.create();
    }

    class ProxyCallBackHandler implements MethodInterceptor {

        @Override
        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            return doIntercept(method, args);
        }

        /**
         * 拦截RCP接口调用
         *
         * @param method
         * @param parameters
         * @return
         * @throws Throwable
         */
        private Object doIntercept(Method method, Object[] parameters) throws Throwable {
            String requestId = RequestIdUtil.requestId();
            String className = method.getDeclaringClass().getName();
            String methodName = method.getName();
            Class<?>[] parameterTypes = method.getParameterTypes();
            // 1. 构建RPC请求信息
            RpcRequest znsRequest = RpcRequest.builder()
                    .requestId(requestId)
                    .className(className)
                    .methodName(methodName)
                    .parameterTypes(parameterTypes)
                    .parameters(parameters)
                    .build();
            // 2. 采用异步方式请求调用
            RpcRequestManager.sendRequest(znsRequest);
            // 3. 通过RCP请求连接记录， 获取调用结果
            RpcResponse znsResponse = rpcRequestPool.fetchResponse(requestId);
            if (znsResponse == null) {
                return null;
            }

            if (znsResponse.isError()) {
                throw znsResponse.getCause();
            }
            // 4. 返回请求调用结果
            return znsResponse.getResult();
        }
    }
}


/**
 * 动态代理拦截处理器，非异步实现
 */
//@Component
//public class ProxyHelper {
//
//    /**
//     * 创建新的代理实例-CGLib动态代理
//     * @param cls
//     * @param <T>
//     * @return
//     */
//    public <T> T newProxyInstance(Class<T> cls) {
//        Enhancer enhancer = new Enhancer();
//        enhancer.setSuperclass(cls);
//        enhancer.setCallback(new ProxyCallBackHandler());
//        return (T) enhancer.create();
//    }
//
//    /**
//     * 代理拦截实现
//     */
//    class ProxyCallBackHandler implements MethodInterceptor {
//
//        @Override
//        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//            return doIntercept(method, args);
//        }
//
//        /**
//         * 拦截RCP接口调用
//         * @param method
//         * @param parameters
//         * @return
//         * @throws Throwable
//         */
//        private Object doIntercept(Method method, Object[] parameters) throws Throwable {
//            //1、封装RpcRequest请求参数
//            String requestId = RequestIdUtil.requestId(); //唯一会话ID
//            String methodName = method.getName();
//            String className = method.getDeclaringClass().getName();
//            Class<?>[] parameterTypes = method.getParameterTypes();
//
//            RpcRequest request = RpcRequest.builder()
//                    .requestId(requestId)
//                    .className(className)
//                    .methodName(methodName)
//                    .parameterTypes(parameterTypes)
//                    .parameters(parameters)
//                    .build();
//
//            //2、发送数据
//            RpcResponse respon = RpcRequestManager.sendRequest(request);
//
//            //3、获取返回结果
//            return respon.getResult();
//        }
//    }
//}